package rest

import (
	"fmt"
	"gsc-datasets/internal/conf"
	dao "gsc-datasets/internal/db/dao"
	"net/http"
	"time"

	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
	"github.com/go-chi/cors"
	"github.com/go-chi/render"
	"go.uber.org/zap"

	// appMiddleware "gsc-datasets/internal/rest/middlewares"
	"gsc-datasets/frontend"
	"gsc-datasets/internal/rest/routers"
	datasetRoute "gsc-datasets/internal/rest/routers/api/dataset"
	datasetEntryRoute "gsc-datasets/internal/rest/routers/api/dataset/entry"
	datasetAnnotationRoute "gsc-datasets/internal/rest/routers/api/dataset/annotation"
	userRoute "gsc-datasets/internal/rest/routers/api/user"
	"gsc-datasets/pkg/util"
)

type RestServer struct {
	slog *zap.SugaredLogger
	sms  *conf.SmsSection
	cos  *conf.CosSection
	dao  *dao.PgDao
	r    chi.Router
	url  string
}

func NewRestServer(slog *zap.SugaredLogger, pgConfPtr *conf.PgSection, webConfPtr *conf.WebSection, sms *conf.SmsSection, cos *conf.CosSection) (s *RestServer) {
	s = &RestServer{
		slog: slog.With("service", "rest"),
		sms:  sms,
		cos:  cos,
		dao:  dao.New(pgConfPtr, slog),
	}
	s.r = chi.NewRouter()
	s.registerRouter()
	s.url = fmt.Sprintf("%s:%s", webConfPtr.Host, webConfPtr.Port)

	return s
}

func (s *RestServer) Run() {
	s.slog.Infof("rest server started on %s ...", s.url)
	if err := http.ListenAndServe(s.url, s.r); err != nil {
		s.slog.Errorf("rest server err %s", err.Error())
	}
}

func (s *RestServer) registerRouter() {

	// A good base middleware stack
	s.r.Use(middleware.RequestID)
	// s.r.Use(appMiddleware.WithWriteRes())
	s.r.Use(middleware.RealIP)
	s.r.Use(middleware.Logger)
	s.r.Use(middleware.Recoverer)
	s.r.Use(middleware.Timeout(60 * time.Second))
	s.r.Use(render.SetContentType(render.ContentTypeJSON))
	s.r.Use(cors.Handler(cors.Options{
		// AllowedOrigins:   []string{"https://foo.com"}, // Use this to allow specific origin hosts
		AllowedOrigins: []string{"https://*", "http://*"},
		// AllowOriginFunc:  func(r *http.Request, origin string) bool { return true },
		AllowedMethods:   []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
		AllowedHeaders:   []string{"X-PINGOTHER", "Accept", "Authorization", "Content-Type", "X-CSRF-Token", util.MockIDKey, util.RequestIDKey},
		ExposedHeaders:   []string{"Link"},
		AllowCredentials: true,
		MaxAge:           300, // Maximum value not ignored by any of major browsers
	}))


	// pingR := chi.NewRouter()
	// pingR.Get("/", func(w http.ResponseWriter, r *http.Request) {
	// 	w.Write([]byte("ok"))
	// })
	// s.r.Mount("/_ping", pingR)
	
	s.r.Get("/_ping", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("ok"))
	})
	userRouter := userRoute.New(routers.New(s.slog, s.dao, s.sms, s.cos))
	s.r.Mount("/api/user", userRouter.ChiRouter())

	datasetRouter := datasetRoute.New(routers.New(s.slog, s.dao, s.sms, s.cos))
	s.r.Mount("/api/dataset", datasetRouter.ChiRouter())

	datasetEntryRouter := datasetEntryRoute.New(routers.New(s.slog, s.dao, s.sms, s.cos))
	s.r.Mount("/api/dataset/{dataset}/entry", datasetEntryRouter.ChiRouter())

	datasetAnnotationRouter := datasetAnnotationRoute.New(routers.New(s.slog, s.dao, s.sms, s.cos))
	s.r.Mount("/api/dataset/{dataset}/annotation", datasetAnnotationRouter.ChiRouter())

	s.r.Mount("/", frontend.SvelteKitHandler("/"))
}
